package com.lokiy.core.ext

import android.util.Log
import com.lokiy.core.BuildConfig

/**
 * Log
 * @author Lokiy
 * @date 2024-04-24
 */

val debug = BuildConfig.DEBUG
private val printStack = false

fun logV(msg: String?) {
    println(Log.VERBOSE, null, msg)
}

fun logV(tag: String? = null, msg: String?) {
    println(Log.VERBOSE, tag, msg)
}

fun logD(msg: String?) {
    println(Log.DEBUG, null, msg)
}

fun logD(tag: String? = null, msg: String?) {
    println(Log.DEBUG, tag, msg)
}

fun logI(msg: String?) {
    println(Log.INFO, null, msg)
}

fun logI(tag: String? = null, msg: String?) {
    println(Log.INFO, tag, msg)
}

fun logW(msg: String?) {
    println(Log.WARN, null, msg)
}

fun logW(tag: String? = null, msg: String?) {
    println(Log.WARN, tag, msg)
}

fun logE(msg: String?) {
    println(Log.ERROR, null, msg)
}

fun logE(tag: String? = null, msg: String?) {
    println(Log.ERROR, tag, msg)
}


private fun println(priority: Int, tag: String?, msg: String?) {
    if (debug && msg != null) {
        val stackTrace = IllegalAccessException().stackTrace
        Log.println(priority, tag ?: getTagName(stackTrace), getMsgPrefix(stackTrace, tag != null, msg) + "" + msg)
    }
}

private fun getTagName(stackTrace: Array<StackTraceElement>): String {
    return stackTrace[2].className.let { className ->
        val indexOf = className.indexOf("$")
        className.substring(0, if (indexOf != -1) indexOf else className.length).let { it1 ->
            it1.substring(it1.indexOfLast { it == '.' }.takeIf { it >= 0 }?.let { it + 1 } ?: 0, it1.length)
        }
    }
}

/**
 * @param isNeedShowClass 是否需要在消息开始显示目标类的名字  如果设置了tag就显示类名字，如果没有设置是会自动生成一个文件类名的tag，故而就不需要显示在首位了
 * @param msg 当前要打印的消息
 */
private fun getMsgPrefix(stackTrace: Array<StackTraceElement>, isNeedShowClass: Boolean, msg: String?): String {
    val firstStack = if (printStack) {
        val s = stackTrace[4].takeIf { it.methodName != "run" && it.methodName != "invokeSuspend" }?.getMsg(isNeedShowClass, "") ?: ""
        s
    } else ""
    return firstStack + stackTrace[2].getMsg(isNeedShowClass, msg)
}

private fun StackTraceElement.getMsg(isNeedShowClass: Boolean, msg: String?) = let {
    val className = if (isNeedShowClass) (it.className.substring(it.className.lastIndexOf(".") + 1) + ".") else ""
    "$className${it.methodName} (${it.fileName}:${it.lineNumber}) ${if (msg.isNullOrEmpty()) "" else "->"} "
}
